package com.gitee.bluebird;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ThreadFactory;

/**
 * * @createtime : 2018/11/26 5:41 PM
 **/
public class RegistryServer implements Closeable {

    private EventLoopGroup parentGroup;
    private EventLoopGroup childGroup;

    private Channel remoteChannel;

    private CommandHandler commandHandler;

    private static final Logger LOG = LoggerFactory.getLogger("RegistryServer");

    public RegistryServer(CommandHandler commandHandler, BootstrapConf bootstrapConf) {

        boolean useEpoll = Epoll.isAvailable();
        if (parentGroup == null) {
            parentGroup = createEventLoopGroup(useEpoll, bootstrapConf.getParentThreadNum(), "REGISTRY-SERVER-PARENT");
        }

        if (childGroup == null) {
            childGroup = createEventLoopGroup(useEpoll, bootstrapConf.getChildThreadNum(), "REGISTRY-SERVER-CHILD");
        }

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(parentGroup, childGroup);
        bootstrap.channel(useEpoll ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
        bootstrap.childHandler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ch.pipeline().addLast(new NettyDecoder(bootstrapConf));
                ch.pipeline().addLast(new NettyEncoder());
                ch.pipeline().addLast(new SimpleChannelInboundHandler<Packet>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Packet packet) throws Exception {
                        commandHandler.getCommand(packet.getCode()).execute(channelHandlerContext, packet);
                    }

                });
            }
        });

        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
        bootstrap.localAddress(bootstrapConf.getServerPort());
        try {
            remoteChannel = bootstrap.bind().sync().channel();
            LOG.info("start server at:{}", ((InetSocketAddress) remoteChannel.localAddress()).getPort());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private EventLoopGroup createEventLoopGroup(boolean useEpoll, int threadNum, String threadPoolName) {
        ThreadFactory threadFactory = new DefaultThreadFactory(threadPoolName, false);
        return useEpoll ? new EpollEventLoopGroup(threadNum, threadFactory) : new NioEventLoopGroup(threadNum, threadFactory);
    }

    @Override
    public void close() throws IOException {

        if (parentGroup != null) {
            parentGroup.shutdownGracefully();
        }

        if (childGroup != null) {
            childGroup.shutdownGracefully();
        }
    }
}
